// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** File:    RealProxy.cs 
**
** 
** Purpose: Defines the base class from which proxy should
**          derive
**
** 
===========================================================*/
namespace System.Runtime.Remoting.Proxies { 
    using System; 
    using System.Reflection;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Metadata; 
    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Services; 
    using System.Runtime.Serialization;
    using System.Runtime.Versioning; 
    using System.Security;
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.Threading; 
    using System.Runtime.ConstrainedExecution;
    using System.Globalization; 
    using System.Diagnostics.Contracts; 

 
    // NOTE: Keep this in [....] with unmanaged enum definition in Remoting.h
    [Serializable]
    internal enum CallType
    { 
        InvalidCall     = 0x0,
        MethodCall      = 0x1, 
        ConstructorCall = 0x2 
    };
 
    [Flags]
    internal enum RealProxyFlags
    {
        None                = 0x0, 
        RemotingProxy       = 0x1,
        Initialized         = 0x2 
    }; 

    // NOTE: Keep this in [....] with unmanaged struct "messageData" in Remoting.h 
    [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
    internal struct MessageData
    {
        internal IntPtr      pFrame; 
        internal IntPtr      pMethodDesc;
        internal IntPtr      pDelegateMD; 
        internal IntPtr      pSig; 
        internal IntPtr      thGoverningType;
        internal int         iFlags; 
    };


 
    [System.Security.SecurityCritical]  // auto-generated_required
    [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
    [System.Runtime.InteropServices.ComVisible(true)] 
    abstract public class RealProxy
    { 
        // ************* NOTE ******
        // Object.h has unmanaged structure which maps this layout
        // if you add/remove/change fields make sure to update the structure
        // in object.h also 

        // Private members 
        private Object _tp; 

        private Object _identity; 

        private MarshalByRefObject _serverObject;

        private RealProxyFlags _flags; 

        internal GCHandle   _srvIdentity; 
 
        internal int        _optFlags;
 
        internal int        _domainID;

        // Static members
        private static IntPtr _defaultStub      = GetDefaultStub(); 

        private static IntPtr _defaultStubValue    = new IntPtr(-1); 
 
        private static Object _defaultStubData  = _defaultStubValue;
 
        [System.Security.SecuritySafeCritical] // static constructors should be safe to call
        static RealProxy()
        {
        } 

        // Constructor 
        [System.Security.SecurityCritical]  // auto-generated 
        protected RealProxy(Type classToProxy) : this(classToProxy, (IntPtr)0, null)
        { 
        }

        [System.Security.SecurityCritical]  // auto-generated_required
        protected RealProxy(Type classToProxy, IntPtr stub, Object stubData) 
        {
            if(!classToProxy.IsMarshalByRef && !classToProxy.IsInterface) 
            { 
                throw new ArgumentException(
                    Environment.GetResourceString("Remoting_Proxy_ProxyTypeIsNotMBR")); 
            }
            Contract.EndContractBlock();

            if((IntPtr)0 == stub) 
            {
                Contract.Assert((IntPtr)0 != _defaultStub, "Default stub not set up"); 
 
                // The default stub checks for match of contexts defined by us
                stub = _defaultStub; 
                // Start with a value of -1 because 0 is reserved for the default context
                stubData = _defaultStubData;
            }
 
            _tp = null;
            if (stubData == null) 
            { 
                throw new ArgumentNullException("stubdata");
            } 
            _tp = RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);
            RemotingProxy rp = this as RemotingProxy;
            if (rp != null)
            { 
                _flags |= RealProxyFlags.RemotingProxy;
            } 
        } 

        // This is used (along the frequent path) of Invoke to avoid 
        // casting to RemotingProxy
        internal bool IsRemotingProxy()
        {
            return (_flags & RealProxyFlags.RemotingProxy) == RealProxyFlags.RemotingProxy; 
        }
 
        // This is mainly used for RemotingProxy case. It may be worthwhile 
        // to make this virtual so extensible proxies can make use of this
        // (and other flags) as well. 
        internal bool Initialized
        {

            get { return (_flags & RealProxyFlags.Initialized) == RealProxyFlags.Initialized; } 
            set
            { 
                if (value) 
                {
                    _flags |= RealProxyFlags.Initialized; 
                }
                else
                {
                    _flags &= ~RealProxyFlags.Initialized; 
                }
            } 
        } 

        // Method to initialize the server object for x-context scenarios 
        // in an extensible way
        [System.Security.SecurityCritical]  // auto-generated_required
        [System.Runtime.InteropServices.ComVisible(true)]
        public IConstructionReturnMessage InitializeServerObject(IConstructionCallMessage ctorMsg) 
        {
            IConstructionReturnMessage retMsg = null; 
 
            if (_serverObject == null)
            { 
                Type svrType = GetProxiedType();
                if((ctorMsg != null) && (ctorMsg.ActivationType != svrType))
                {
                    throw new RemotingException( 
                        String.Format(
                            CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Proxy_BadTypeForActivation"), 
                                                          svrType.FullName, 
                                                          ctorMsg.ActivationType));
                } 

                // Create a blank object
                _serverObject = RemotingServices.AllocateUninitializedObject(svrType);
 
                // If the stub is the default stub, then set the server context
                // to be the current context. 
                SetContextForDefaultStub(); 

                // OK... we are all set to run the constructor call on the uninitialized object 
                MarshalByRefObject proxy = (MarshalByRefObject)GetTransparentProxy();
                IMethodReturnMessage  msg = null;
                Exception e = null;
                if(null != ctorMsg) 
                {
                    msg = RemotingServices.ExecuteMessage(proxy, ctorMsg); 
                    e = msg.Exception; 
                }
                else 
                {
                    try
                    {
                        RemotingServices.CallDefaultCtor(proxy); 
                    }
                    catch(Exception excep) 
                    { 
                        e = excep;
                    } 
                }

                // Construct a return message
                if(null == e) 
                {
                    Object[] outArgs = (msg == null ? null : msg.OutArgs); 
                    int outLength = (null == outArgs ? 0 : outArgs.Length); 
                    LogicalCallContext callCtx = (msg == null ? null : msg.LogicalCallContext);
                    retMsg = new ConstructorReturnMessage(proxy, 
                                                          outArgs, outLength,
                                                          callCtx, ctorMsg);

                    // setup identity 
                    SetupIdentity();
                    if (IsRemotingProxy()) 
                    { 
                        ((RemotingProxy) this).Initialized = true;
                    } 
                }
                else
                {
                    // Exception occurred 
                    retMsg = new ConstructorReturnMessage(e, ctorMsg);
                } 
            } 

 
            return retMsg;
        }

        [System.Security.SecurityCritical]  // auto-generated_required 
        protected MarshalByRefObject GetUnwrappedServer()
        { 
            return UnwrappedServerObject; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated_required
        protected MarshalByRefObject DetachServer()
        {
            Object tp = GetTransparentProxy(); 
            if (tp != null)
                RemotingServices.ResetInterfaceCache(tp); 
            MarshalByRefObject server = _serverObject; 
            _serverObject = null;
            server.__ResetServerIdentity(); 
            return server;
        }

        [System.Security.SecurityCritical]  // auto-generated_required 
        protected void AttachServer(MarshalByRefObject s)
        { 
            Object tp = GetTransparentProxy(); 
            if (tp != null)
                RemotingServices.ResetInterfaceCache(tp); 
            AttachServerHelper(s);
        }

        [System.Security.SecurityCritical]  // auto-generated 
        private void SetupIdentity()
        { 
            if (_identity == null) 
            {
                _identity = IdentityHolder.FindOrCreateServerIdentity( 
                                (MarshalByRefObject)_serverObject,
                                null,
                                IdOps.None);
                // Set the reference to the proxy in the identity object 
                  ((Identity)_identity).RaceSetTransparentProxy(GetTransparentProxy());
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        private void SetContextForDefaultStub()
        {
            // Check whether the stub is ours or not...
            if(GetStub() == _defaultStub) 
            {
                // Yes.. setup the context in the TP so that 
                // contexts can be matched correctly... 
                Object oVal = GetStubData(this);
                if(oVal is IntPtr) 
                {
                    IntPtr iVal = (IntPtr)oVal;

                    // Set the stub data only if it has been set to our default value, 
                    // otherwise, the user has already indicated a preference for the
                    // stub data. 
                    if(iVal.Equals(_defaultStubValue)) 
                    {
                        SetStubData(this, Thread.CurrentContext.InternalContextID); 
                    }
                }
            }
        } 

 
        // Check whether the current context is the same as the 
        // server context
        [System.Security.SecurityCritical]  // auto-generated 
        internal bool DoContextsMatch()
        {
            bool fMatch = false;
 
            // Check whether the stub is ours or not...
            if(GetStub() == _defaultStub) 
            { 
                // Yes.. setup the context in the TP so that
                // contexts can be matched correctly... 
                Object oVal = GetStubData(this);
                if(oVal is IntPtr)
                {
                    IntPtr iVal = (IntPtr)oVal; 
                    // Match the internal context ids...
                    if(iVal.Equals(Thread.CurrentContext.InternalContextID)) 
                    { 
                        fMatch = true;
                    } 
                }
            }

            return fMatch; 
        }
 
        // This is directly called by RemotingServices::Wrap() when it needs 
        // to bind a proxy with an uninitialized contextBound server object
        [System.Security.SecurityCritical]  // auto-generated 
        internal void AttachServerHelper(MarshalByRefObject s)
        {
            if (s == null || _serverObject != null)
            { 
                throw new ArgumentException(Environment.GetResourceString("ArgumentNull_Generic"), "s");
            } 
            _serverObject = s; 
            // setup identity
            SetupIdentity(); 
        }

        // Gets the stub pointer stashed away in the transparent proxy.
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern IntPtr GetStub(); 
 
        // Sets the stub data
        [System.Security.SecurityCritical]  // auto-generated_required 
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void SetStubData(RealProxy rp, Object stubData);
 
        internal void SetSrvInfo(GCHandle srvIdentity, int domainID)
        { 
            _srvIdentity = srvIdentity; 
            _domainID = domainID;
        } 

        // Gets the stub data
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Object GetStubData(RealProxy rp); 
 
        // Gets the default stub implemented by us
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern IntPtr GetDefaultStub();

 
        // Accessor to obtain the type being proxied
        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern Type GetProxiedType(); 

        // Method to which transparent proxy delegates when
        // it gets called
        public abstract IMessage Invoke(IMessage msg); 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual ObjRef CreateObjRef(Type requestedType) 
        {
            if(_identity == null) 
            {
                throw new RemotingException(Environment.GetResourceString(
                    "Remoting_NoIdentityEntry"));
            } 

            return new ObjRef((MarshalByRefObject)GetTransparentProxy(), requestedType); 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            Object obj = GetTransparentProxy();
            RemotingServices.GetObjectData(obj, info, context); 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        private static void HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
        { 
            IMethodReturnMessage mrm = retMsg as IMethodReturnMessage;
            if (retMsg==null || (mrm == null))
            {
                throw new RemotingException(Environment.GetResourceString( 
                        "Remoting_Message_BadType"));
            } 
 
            Exception e = mrm.Exception;
 
            if (e != null)
            {
                throw e.PrepForRemoting();
            } 
            else
            { 
                if (!(retMsg is StackBasedReturnMessage)) 
                {
                    if (reqMsg is Message) 
                    {
                        PropagateOutParameters(reqMsg, mrm.Args, mrm.ReturnValue);
                    }
                    else if (reqMsg is ConstructorCallMessage) 
                    {
                        // NOTE: We do not extract the return value as 
                        // the process of returning a value from a ConstructorCallMessage 
                        // results in marshaling.
                        PropagateOutParameters(reqMsg, mrm.Args, null); 
                    }
                }
            }
        } 

        // Propagate the out parameters to the stack. This should be called once 
        // the call has finished. The input message parameter should be the same 
        // as the one which was passed to the first sink to start the call.
        [System.Security.SecurityCritical]  // auto-generated 
        internal static void PropagateOutParameters(IMessage msg,
                                                    Object[] outArgs,
                                                    Object returnValue)
        { 
            // Check for method call
            Message m = msg as Message; 
 
            // Check for constructor call
            if(null == m) 
            {
                ConstructorCallMessage ccm = msg as ConstructorCallMessage;
                if(null != ccm)
                { 
                    m = ccm.GetMessage();
                } 
            } 

            if(null == m) 
            {
                throw new ArgumentException(
                    Environment.GetResourceString("Remoting_Proxy_ExpectedOriginalMessage"));
            } 

            MethodBase mb = m.GetMethodBase(); 
            RemotingMethodCachedData cache = 
                    InternalRemotingServices.GetReflectionCachedData(mb);
            if (outArgs != null && outArgs.Length > 0) 
            {
                Object[] args = m.Args; // original arguments

                // If a byref parameter is marked only with [In], we need to copy the 
                //   original value from the request message into outargs, so that the
                //   value won't be bashed by CMessage::PropagateOutParameters below. 
                ParameterInfo[] parameters = cache.Parameters; 
                foreach (int index in cache.MarshalRequestArgMap)
                { 
                    ParameterInfo param = parameters[index];
                    if (param.IsIn && param.ParameterType.IsByRef)
                    {
                        if (!param.IsOut) 
                            outArgs[index] = args[index];
                    } 
                } 

                // copy non-byref arrays back into the same instance 
                if (cache.NonRefOutArgMap.Length > 0)
                {
                    foreach (int index in cache.NonRefOutArgMap)
                    { 
                        Array arg = args[index] as Array;
                        if (arg != null) 
                        { 
                            Array.Copy((Array)outArgs[index], arg, arg.Length);
                        } 
                    }
                }

                // validate by-ref args (This must be done last) 
                int[] outRefArgMap = cache.OutRefArgMap;
                if (outRefArgMap.Length > 0) 
                { 
                    foreach (int index in outRefArgMap)
                    { 
                        ValidateReturnArg(outArgs[index], parameters[index].ParameterType);
                    }
                }
            } 

            // validate return value 
            //   (We don't validate Message.BeginAsync because the return value 
            //    is always an IAsyncResult and the method base is the one that
            //    represents the underlying synchronous method). 
            int callType = m.GetCallType();
            if ((callType & Message.CallMask ) != Message.BeginAsync)
            {
                Type returnType = cache.ReturnType; 
                if (returnType != null)
                { 
                    ValidateReturnArg(returnValue, returnType); 
                }
            } 

            m.PropagateOutParameters(outArgs, returnValue);
        } // PropagateOutParameters
 
        private static void ValidateReturnArg(Object arg, Type paramType)
        { 
            if (paramType.IsByRef) 
                paramType = paramType.GetElementType();
 
            if (paramType.IsValueType)
            {
                if (arg == null)
                { 
                    if (!(paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                        throw new RemotingException( 
                            Environment.GetResourceString("Remoting_Proxy_ReturnValueTypeCannotBeNull")); 
                }
                else if (!paramType.IsInstanceOfType(arg)) 
                {
                    throw new InvalidCastException(
                        Environment.GetResourceString("Remoting_Proxy_BadReturnType"));
                } 
            }
            else 
            { 
                if (arg != null)
                { 
                    if (!paramType.IsInstanceOfType(arg))
                    {
                        throw new InvalidCastException(
                            Environment.GetResourceString("Remoting_Proxy_BadReturnType")); 
                    }
                } 
            } 
        } // ValidateReturnArg
 
        // This is shared code path that executes when an EndInvoke is called
        // either on a delegate on a proxy
        // OR a regular delegate (called asynchronously).
        [System.Security.SecurityCritical]  // auto-generated 
        internal static IMessage EndInvokeHelper(Message reqMsg, bool bProxyCase)
        { 
            AsyncResult ar = reqMsg.GetAsyncResult() as AsyncResult; 
            IMessage retMsg = null; // used for proxy case only!
            if (ar == null) 
            {
                throw new RemotingException(
                    Environment.GetResourceString(
                        "Remoting_Message_BadAsyncResult")); 
            }
            if (ar.AsyncDelegate != reqMsg.GetThisPtr()) 
            { 
                throw new InvalidOperationException(Environment.GetResourceString(
                    "InvalidOperation_MismatchedAsyncResult")); 
            }
            if (!ar.IsCompleted)
            {
                // Note: using ThreadPoolAware to detect if this is a 
                // ThreadAffinity or Synchronization context.
                ar.AsyncWaitHandle.WaitOne( 
                        Int32.MaxValue, 
                        Thread.CurrentContext.IsThreadPoolAware);
            } 

            lock (ar)
            {
                if (ar.EndInvokeCalled) 
                    throw new InvalidOperationException(
                        Environment.GetResourceString( 
                            "InvalidOperation_EndInvokeCalledMultiple")); 

                ar.EndInvokeCalled = true; 


                IMethodReturnMessage mrm =
                    (IMethodReturnMessage) ar.GetReplyMessage(); 

                Contract.Assert( 
                    mrm != null, 
                    "Reply sink should ensure we have a reply message before signalling");
 
                // For the proxy case this is handled by RealProxy
                if (!bProxyCase)
                {
                    Exception e = mrm.Exception; 

                    if (e != null) 
                    { 
                        // throw e;
                        throw e.PrepForRemoting(); 
                    }
                    else
                    {
                        reqMsg.PropagateOutParameters( 
                            mrm.Args,
                            mrm.ReturnValue); 
                    } 
                }
                else 
                {
                    retMsg = mrm;
                }
                // Merge the call context back into the thread that 
                // called EndInvoke
                CallContext.GetLogicalCallContext().Merge( 
                    mrm.LogicalCallContext); 
            }
            // Will be non-null only for proxy case! 
            return retMsg;
        } // EndInvokeHelper

#if FEATURE_COMINTEROP 
        // itnerop methods
        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IntPtr GetCOMIUnknown(bool fIsMarshalled) 
        {
            // sub -class should override 
            return MarshalByRefObject.GetComIUnknown((MarshalByRefObject)GetTransparentProxy());
        }

        public virtual void SetCOMIUnknown(IntPtr i) 
        {
            // don't care 
        } 

        public virtual IntPtr SupportsInterface(ref Guid iid) 
        {
            return IntPtr.Zero;
        }
#endif // FEATURE_COMINTEROP 

        // Method used for traversing back to the TP 
        public virtual Object GetTransparentProxy() 
        {
            return _tp; 
        }

        internal MarshalByRefObject UnwrappedServerObject
        { 
            get { return (MarshalByRefObject) _serverObject; }
        } 
 
        internal virtual Identity IdentityObject
        { 
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            get
            {
                return (Identity) _identity; 
            }
 
            set 
            {
                _identity = value; 
            }
        }

        // Private method invoked by the transparent proxy 
        [System.Security.SecurityCritical]  // auto-generated
        private void PrivateInvoke(ref MessageData msgData, int type) 
        { 
            IMessage reqMsg = null;
            CallType callType = (CallType)type; 
            IMessage retMsg = null;
            int msgFlags = -1;

            // Used only for Construction case 
            RemotingProxy rp = null;
 
            // Create a message object based on the type of call 
            if(CallType.MethodCall == callType)
            { 
                Message msg = new Message();
                msg.InitFields(msgData);
                reqMsg = msg;
                msgFlags = msg.GetCallType(); 
            }
            else if (CallType.ConstructorCall == (CallType)callType) 
            { 
                // We use msgFlags to handle CallContext around
                // the virtual call to Invoke() 
                msgFlags = Message.[....];

                rp = this as RemotingProxy;
                ConstructorCallMessage ctorMsg = null; 
                bool bIsWellKnown = false;
                if(!IsRemotingProxy()) 
                { 
                    // Create a new constructor call message
                    // < 

                    ctorMsg = new ConstructorCallMessage(null, null, null, (RuntimeType)GetProxiedType());
                }
                else 
                {
                    // Extract the constructor message set in the first step of activation. 
                    ctorMsg = rp.ConstructorMessage; 
                    // If the proxy is a wellknown client proxy, we don't
                    // need to run the c'tor. 
                    Identity id = rp.IdentityObject;
                    if (id != null)
                        bIsWellKnown = id.IsWellKnown();
                } 

                if ((null == ctorMsg) || bIsWellKnown) 
                { 
                    // This is also used to short-circuit the activation path
                    // when we have a well known proxy that has already been 
                    // initialized (there's a race condition if we don't do this).
                    //

                    // This is a special case, where we have a remoting proxy 
                    // but the constructormessage hasn't been setup.
                    // so let us just bail out.. 
                    // this is currently used by ServicedComponent's for cross appdomain 
                    // pooling: <EMAIL>[....]</EMAIL>
                    // 
                    ctorMsg = new ConstructorCallMessage(null, null, null, (RuntimeType)GetProxiedType());
                    // Set the constructor frame info in the CCM
                    ctorMsg.SetFrame(msgData);
                    reqMsg = ctorMsg; 

                    // If this was the default ctor, check that default .ctor was called. 
                    if (bIsWellKnown) 
                    {
                        Contract.Assert(rp!=null, "RemotingProxy expected here!"); 
                        // Clear any cached ctorMsg on the RemotingProxy
                        rp.ConstructorMessage = null;

                        // We did execute a Connect. Throw if the client 
                        // code is also trying to use a non-default constructor at
                        // the same time. 
                        if (ctorMsg.ArgCount != 0) 
                        {
                            throw new RemotingException( 
                                Environment.GetResourceString(
                                    "Remoting_Activation_WellKnownCTOR"));
                        }
                    } 

                    // Create a constructor return message 
                    retMsg = 
                        new ConstructorReturnMessage((MarshalByRefObject)GetTransparentProxy(),
                            null, 
                            0,
                            null,
                            ctorMsg);
                } 
                else
                { 
                    // Set the constructor frame info in the CCM 
                    ctorMsg.SetFrame(msgData);
                    reqMsg = ctorMsg; 
                }
            }
            else
            { 
                Contract.Assert(false, "Unknown call type");
            } 
 
            // Make sure that outgoing remote calls are counted.
            ChannelServices.IncrementRemoteCalls(); 

            // For non-remoting proxies, EndAsync should not call Invoke()
            // because the proxy cannot support Async and the call has already
            // finished executing in BeginAsync 
            if (!IsRemotingProxy()
                && ((msgFlags&Message.EndAsync)==Message.EndAsync)) 
            { 

                Message msg = reqMsg as Message; 
                retMsg = EndInvokeHelper(msg, true);
                Contract.Assert(null != retMsg, "null != retMsg");
            }
 
            // Invoke
            Contract.Assert(null != reqMsg, "null != reqMsg"); 
            if (null == retMsg) 
            {
                // NOTE: there are cases where we setup a return message 
                // and we don't want the activation call to go through
                // refer to the note above for ServicedComponents and Cross Appdomain
                // pooling
 
                LogicalCallContext cctx = null;
                Thread currentThread = Thread.CurrentThread; 
                // Pick up or clone the call context from the thread 
                // and install it in the reqMsg as appropriate
                cctx = currentThread.GetLogicalCallContext(); 
                SetCallContextInMessage(reqMsg, msgFlags, cctx);

                // Add the outgoing "Header"'s to the message.
                cctx.PropagateOutgoingHeadersToMessage(reqMsg); 
                retMsg = Invoke(reqMsg);
 
                // Get the call context returned and set it on the thread 
                ReturnCallContextToThread(currentThread, retMsg, msgFlags, cctx);
 
                // Pull response "Header"'s out of the message
                CallContext.GetLogicalCallContext().PropagateIncomingHeadersToCallContext(retMsg);
            }
 
            if (!IsRemotingProxy()
                && ((msgFlags&Message.BeginAsync) == Message.BeginAsync)) 
            { 

                // This was a begin-async on a non-Remoting Proxy. For V-1 they 
                // cannot support Async and end up doing a [....] call. We need
                // to fill up here to make the call look like async to
                // the caller.
                // Create the async result to return 
                Message msg = reqMsg as Message;
                AsyncResult ar = new AsyncResult(msg); 
                // Tell the async result that the call has actually completed 
                // so it can hold on to the return message.
                ar.SyncProcessMessage(retMsg); 
                // create a returnMessage to propagate just the asyncResult back
                // to the caller's stack.
                retMsg = new ReturnMessage(ar, null, 0, null/*cctx*/, msg);
            } 

            // Propagate out parameters 
            HandleReturnMessage(reqMsg, retMsg); 

            // For constructor calls do some extra bookkeeping 
            if(CallType.ConstructorCall == callType)
            {
                // NOTE: It is the responsiblity of the callee to propagate
                // the out parameters 

                // Everything went well, we are ready to return 
                // a proxy to the caller 
                // Extract the return value
                MarshalByRefObject retObj = null; 
                IConstructionReturnMessage ctorRetMsg = retMsg as IConstructionReturnMessage;
                if(null == ctorRetMsg)
                {
                    throw new RemotingException( 
                        Environment.GetResourceString("Remoting_Proxy_BadReturnTypeForActivation"));
                } 
 
                ConstructorReturnMessage crm = ctorRetMsg as ConstructorReturnMessage;
                if (null != crm) 
                {
                    // If return message is of type ConstructorReturnMessage
                    // this is an in-appDomain activation. So no unmarshaling
                    // needed. 

                    retObj = (MarshalByRefObject)crm.GetObject(); 
                    if (retObj == null) 
                    {
                        throw new RemotingException( 
                            Environment.GetResourceString("Remoting_Activation_NullReturnValue"));
                    }
                }
                else 
                {
                    // Fetch the objRef out of the returned message and unmarshal it 
                    retObj = (MarshalByRefObject)RemotingServices.InternalUnmarshal( 
                                (ObjRef)ctorRetMsg.ReturnValue,
                                GetTransparentProxy(), 
                                true /*fRefine*/);

                    if (retObj == null)
                    { 
                        throw new RemotingException(
                            Environment.GetResourceString("Remoting_Activation_NullFromInternalUnmarshal")); 
                    } 
                }
 
                if (retObj != (MarshalByRefObject)GetTransparentProxy())
                {
                    throw new RemotingException(
                        Environment.GetResourceString( 
                            "Remoting_Activation_InconsistentState"));
                } 
 
                if (IsRemotingProxy())
                { 
                    // Clear any cached ctorMsg on the RemotingProxy
                    rp.ConstructorMessage = null;
                }
            } 
        }
 
        void SetCallContextInMessage( 
            IMessage reqMsg, int msgFlags, LogicalCallContext cctx)
        { 
            Contract.Assert(msgFlags != -1, "Unexpected msgFlags?");
            Message msg = reqMsg as Message;

            switch (msgFlags) 
            {
            case Message.[....]: 
                if (msg != null) 
                {
                    msg.SetLogicalCallContext(cctx); 
                }
                else
                {
                    ((ConstructorCallMessage)reqMsg).SetLogicalCallContext(cctx); 
                }
                break; 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        void ReturnCallContextToThread(Thread currentThread, IMessage retMsg, int msgFlags, LogicalCallContext currCtx)
        {
            if (msgFlags == Message.[....]) 
            {
                if (retMsg == null) 
                    return; 

                IMethodReturnMessage mrm = retMsg as IMethodReturnMessage; 
                if (mrm == null)
                    return;

                LogicalCallContext retCtx = mrm.LogicalCallContext; 
                if (retCtx == null) {
                    currentThread.SetLogicalCallContext(currCtx); 
                    return; 
                }
 
                if (!(mrm is StackBasedReturnMessage))
                {
                    LogicalCallContext oldCtx = currentThread.SetLogicalCallContext(retCtx);
                    if ((Object)oldCtx != (Object)retCtx) 
                    {
                        // If the new call context does not match the old call context, 
                        //   we must have gone remote. We need to keep the preserve 
                        //   the principal from the original call context.
                        IPrincipal principal = oldCtx.Principal; 
                        if (principal != null)
                            retCtx.Principal = principal;
                    }
                } 
                //for other types (async/one-way etc) there is nothing to be
                //done as we have just finished processing BeginInvoke or EndInvoke 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal virtual void Wrap()
        {
            // < 

 
 
            ServerIdentity serverID = _identity as ServerIdentity;
            if((null != serverID) && (this is RemotingProxy)) 
            {
                Contract.Assert(null != serverID.ServerContext, "null != serverID.ServerContext");
                SetStubData(this, serverID.ServerContext.InternalContextID);
            } 
        }
 
        protected RealProxy() 
        {
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** File:    RealProxy.cs 
**
** 
** Purpose: Defines the base class from which proxy should
**          derive
**
** 
===========================================================*/
namespace System.Runtime.Remoting.Proxies { 
    using System; 
    using System.Reflection;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Metadata; 
    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Services; 
    using System.Runtime.Serialization;
    using System.Runtime.Versioning; 
    using System.Security;
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.Threading; 
    using System.Runtime.ConstrainedExecution;
    using System.Globalization; 
    using System.Diagnostics.Contracts; 

 
    // NOTE: Keep this in [....] with unmanaged enum definition in Remoting.h
    [Serializable]
    internal enum CallType
    { 
        InvalidCall     = 0x0,
        MethodCall      = 0x1, 
        ConstructorCall = 0x2 
    };
 
    [Flags]
    internal enum RealProxyFlags
    {
        None                = 0x0, 
        RemotingProxy       = 0x1,
        Initialized         = 0x2 
    }; 

    // NOTE: Keep this in [....] with unmanaged struct "messageData" in Remoting.h 
    [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
    internal struct MessageData
    {
        internal IntPtr      pFrame; 
        internal IntPtr      pMethodDesc;
        internal IntPtr      pDelegateMD; 
        internal IntPtr      pSig; 
        internal IntPtr      thGoverningType;
        internal int         iFlags; 
    };


 
    [System.Security.SecurityCritical]  // auto-generated_required
    [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
    [System.Runtime.InteropServices.ComVisible(true)] 
    abstract public class RealProxy
    { 
        // ************* NOTE ******
        // Object.h has unmanaged structure which maps this layout
        // if you add/remove/change fields make sure to update the structure
        // in object.h also 

        // Private members 
        private Object _tp; 

        private Object _identity; 

        private MarshalByRefObject _serverObject;

        private RealProxyFlags _flags; 

        internal GCHandle   _srvIdentity; 
 
        internal int        _optFlags;
 
        internal int        _domainID;

        // Static members
        private static IntPtr _defaultStub      = GetDefaultStub(); 

        private static IntPtr _defaultStubValue    = new IntPtr(-1); 
 
        private static Object _defaultStubData  = _defaultStubValue;
 
        [System.Security.SecuritySafeCritical] // static constructors should be safe to call
        static RealProxy()
        {
        } 

        // Constructor 
        [System.Security.SecurityCritical]  // auto-generated 
        protected RealProxy(Type classToProxy) : this(classToProxy, (IntPtr)0, null)
        { 
        }

        [System.Security.SecurityCritical]  // auto-generated_required
        protected RealProxy(Type classToProxy, IntPtr stub, Object stubData) 
        {
            if(!classToProxy.IsMarshalByRef && !classToProxy.IsInterface) 
            { 
                throw new ArgumentException(
                    Environment.GetResourceString("Remoting_Proxy_ProxyTypeIsNotMBR")); 
            }
            Contract.EndContractBlock();

            if((IntPtr)0 == stub) 
            {
                Contract.Assert((IntPtr)0 != _defaultStub, "Default stub not set up"); 
 
                // The default stub checks for match of contexts defined by us
                stub = _defaultStub; 
                // Start with a value of -1 because 0 is reserved for the default context
                stubData = _defaultStubData;
            }
 
            _tp = null;
            if (stubData == null) 
            { 
                throw new ArgumentNullException("stubdata");
            } 
            _tp = RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);
            RemotingProxy rp = this as RemotingProxy;
            if (rp != null)
            { 
                _flags |= RealProxyFlags.RemotingProxy;
            } 
        } 

        // This is used (along the frequent path) of Invoke to avoid 
        // casting to RemotingProxy
        internal bool IsRemotingProxy()
        {
            return (_flags & RealProxyFlags.RemotingProxy) == RealProxyFlags.RemotingProxy; 
        }
 
        // This is mainly used for RemotingProxy case. It may be worthwhile 
        // to make this virtual so extensible proxies can make use of this
        // (and other flags) as well. 
        internal bool Initialized
        {

            get { return (_flags & RealProxyFlags.Initialized) == RealProxyFlags.Initialized; } 
            set
            { 
                if (value) 
                {
                    _flags |= RealProxyFlags.Initialized; 
                }
                else
                {
                    _flags &= ~RealProxyFlags.Initialized; 
                }
            } 
        } 

        // Method to initialize the server object for x-context scenarios 
        // in an extensible way
        [System.Security.SecurityCritical]  // auto-generated_required
        [System.Runtime.InteropServices.ComVisible(true)]
        public IConstructionReturnMessage InitializeServerObject(IConstructionCallMessage ctorMsg) 
        {
            IConstructionReturnMessage retMsg = null; 
 
            if (_serverObject == null)
            { 
                Type svrType = GetProxiedType();
                if((ctorMsg != null) && (ctorMsg.ActivationType != svrType))
                {
                    throw new RemotingException( 
                        String.Format(
                            CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Proxy_BadTypeForActivation"), 
                                                          svrType.FullName, 
                                                          ctorMsg.ActivationType));
                } 

                // Create a blank object
                _serverObject = RemotingServices.AllocateUninitializedObject(svrType);
 
                // If the stub is the default stub, then set the server context
                // to be the current context. 
                SetContextForDefaultStub(); 

                // OK... we are all set to run the constructor call on the uninitialized object 
                MarshalByRefObject proxy = (MarshalByRefObject)GetTransparentProxy();
                IMethodReturnMessage  msg = null;
                Exception e = null;
                if(null != ctorMsg) 
                {
                    msg = RemotingServices.ExecuteMessage(proxy, ctorMsg); 
                    e = msg.Exception; 
                }
                else 
                {
                    try
                    {
                        RemotingServices.CallDefaultCtor(proxy); 
                    }
                    catch(Exception excep) 
                    { 
                        e = excep;
                    } 
                }

                // Construct a return message
                if(null == e) 
                {
                    Object[] outArgs = (msg == null ? null : msg.OutArgs); 
                    int outLength = (null == outArgs ? 0 : outArgs.Length); 
                    LogicalCallContext callCtx = (msg == null ? null : msg.LogicalCallContext);
                    retMsg = new ConstructorReturnMessage(proxy, 
                                                          outArgs, outLength,
                                                          callCtx, ctorMsg);

                    // setup identity 
                    SetupIdentity();
                    if (IsRemotingProxy()) 
                    { 
                        ((RemotingProxy) this).Initialized = true;
                    } 
                }
                else
                {
                    // Exception occurred 
                    retMsg = new ConstructorReturnMessage(e, ctorMsg);
                } 
            } 

 
            return retMsg;
        }

        [System.Security.SecurityCritical]  // auto-generated_required 
        protected MarshalByRefObject GetUnwrappedServer()
        { 
            return UnwrappedServerObject; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated_required
        protected MarshalByRefObject DetachServer()
        {
            Object tp = GetTransparentProxy(); 
            if (tp != null)
                RemotingServices.ResetInterfaceCache(tp); 
            MarshalByRefObject server = _serverObject; 
            _serverObject = null;
            server.__ResetServerIdentity(); 
            return server;
        }

        [System.Security.SecurityCritical]  // auto-generated_required 
        protected void AttachServer(MarshalByRefObject s)
        { 
            Object tp = GetTransparentProxy(); 
            if (tp != null)
                RemotingServices.ResetInterfaceCache(tp); 
            AttachServerHelper(s);
        }

        [System.Security.SecurityCritical]  // auto-generated 
        private void SetupIdentity()
        { 
            if (_identity == null) 
            {
                _identity = IdentityHolder.FindOrCreateServerIdentity( 
                                (MarshalByRefObject)_serverObject,
                                null,
                                IdOps.None);
                // Set the reference to the proxy in the identity object 
                  ((Identity)_identity).RaceSetTransparentProxy(GetTransparentProxy());
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        private void SetContextForDefaultStub()
        {
            // Check whether the stub is ours or not...
            if(GetStub() == _defaultStub) 
            {
                // Yes.. setup the context in the TP so that 
                // contexts can be matched correctly... 
                Object oVal = GetStubData(this);
                if(oVal is IntPtr) 
                {
                    IntPtr iVal = (IntPtr)oVal;

                    // Set the stub data only if it has been set to our default value, 
                    // otherwise, the user has already indicated a preference for the
                    // stub data. 
                    if(iVal.Equals(_defaultStubValue)) 
                    {
                        SetStubData(this, Thread.CurrentContext.InternalContextID); 
                    }
                }
            }
        } 

 
        // Check whether the current context is the same as the 
        // server context
        [System.Security.SecurityCritical]  // auto-generated 
        internal bool DoContextsMatch()
        {
            bool fMatch = false;
 
            // Check whether the stub is ours or not...
            if(GetStub() == _defaultStub) 
            { 
                // Yes.. setup the context in the TP so that
                // contexts can be matched correctly... 
                Object oVal = GetStubData(this);
                if(oVal is IntPtr)
                {
                    IntPtr iVal = (IntPtr)oVal; 
                    // Match the internal context ids...
                    if(iVal.Equals(Thread.CurrentContext.InternalContextID)) 
                    { 
                        fMatch = true;
                    } 
                }
            }

            return fMatch; 
        }
 
        // This is directly called by RemotingServices::Wrap() when it needs 
        // to bind a proxy with an uninitialized contextBound server object
        [System.Security.SecurityCritical]  // auto-generated 
        internal void AttachServerHelper(MarshalByRefObject s)
        {
            if (s == null || _serverObject != null)
            { 
                throw new ArgumentException(Environment.GetResourceString("ArgumentNull_Generic"), "s");
            } 
            _serverObject = s; 
            // setup identity
            SetupIdentity(); 
        }

        // Gets the stub pointer stashed away in the transparent proxy.
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern IntPtr GetStub(); 
 
        // Sets the stub data
        [System.Security.SecurityCritical]  // auto-generated_required 
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void SetStubData(RealProxy rp, Object stubData);
 
        internal void SetSrvInfo(GCHandle srvIdentity, int domainID)
        { 
            _srvIdentity = srvIdentity; 
            _domainID = domainID;
        } 

        // Gets the stub data
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Object GetStubData(RealProxy rp); 
 
        // Gets the default stub implemented by us
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern IntPtr GetDefaultStub();

 
        // Accessor to obtain the type being proxied
        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.None)] 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern Type GetProxiedType(); 

        // Method to which transparent proxy delegates when
        // it gets called
        public abstract IMessage Invoke(IMessage msg); 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual ObjRef CreateObjRef(Type requestedType) 
        {
            if(_identity == null) 
            {
                throw new RemotingException(Environment.GetResourceString(
                    "Remoting_NoIdentityEntry"));
            } 

            return new ObjRef((MarshalByRefObject)GetTransparentProxy(), requestedType); 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            Object obj = GetTransparentProxy();
            RemotingServices.GetObjectData(obj, info, context); 
        }
 
        [System.Security.SecurityCritical]  // auto-generated 
        private static void HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
        { 
            IMethodReturnMessage mrm = retMsg as IMethodReturnMessage;
            if (retMsg==null || (mrm == null))
            {
                throw new RemotingException(Environment.GetResourceString( 
                        "Remoting_Message_BadType"));
            } 
 
            Exception e = mrm.Exception;
 
            if (e != null)
            {
                throw e.PrepForRemoting();
            } 
            else
            { 
                if (!(retMsg is StackBasedReturnMessage)) 
                {
                    if (reqMsg is Message) 
                    {
                        PropagateOutParameters(reqMsg, mrm.Args, mrm.ReturnValue);
                    }
                    else if (reqMsg is ConstructorCallMessage) 
                    {
                        // NOTE: We do not extract the return value as 
                        // the process of returning a value from a ConstructorCallMessage 
                        // results in marshaling.
                        PropagateOutParameters(reqMsg, mrm.Args, null); 
                    }
                }
            }
        } 

        // Propagate the out parameters to the stack. This should be called once 
        // the call has finished. The input message parameter should be the same 
        // as the one which was passed to the first sink to start the call.
        [System.Security.SecurityCritical]  // auto-generated 
        internal static void PropagateOutParameters(IMessage msg,
                                                    Object[] outArgs,
                                                    Object returnValue)
        { 
            // Check for method call
            Message m = msg as Message; 
 
            // Check for constructor call
            if(null == m) 
            {
                ConstructorCallMessage ccm = msg as ConstructorCallMessage;
                if(null != ccm)
                { 
                    m = ccm.GetMessage();
                } 
            } 

            if(null == m) 
            {
                throw new ArgumentException(
                    Environment.GetResourceString("Remoting_Proxy_ExpectedOriginalMessage"));
            } 

            MethodBase mb = m.GetMethodBase(); 
            RemotingMethodCachedData cache = 
                    InternalRemotingServices.GetReflectionCachedData(mb);
            if (outArgs != null && outArgs.Length > 0) 
            {
                Object[] args = m.Args; // original arguments

                // If a byref parameter is marked only with [In], we need to copy the 
                //   original value from the request message into outargs, so that the
                //   value won't be bashed by CMessage::PropagateOutParameters below. 
                ParameterInfo[] parameters = cache.Parameters; 
                foreach (int index in cache.MarshalRequestArgMap)
                { 
                    ParameterInfo param = parameters[index];
                    if (param.IsIn && param.ParameterType.IsByRef)
                    {
                        if (!param.IsOut) 
                            outArgs[index] = args[index];
                    } 
                } 

                // copy non-byref arrays back into the same instance 
                if (cache.NonRefOutArgMap.Length > 0)
                {
                    foreach (int index in cache.NonRefOutArgMap)
                    { 
                        Array arg = args[index] as Array;
                        if (arg != null) 
                        { 
                            Array.Copy((Array)outArgs[index], arg, arg.Length);
                        } 
                    }
                }

                // validate by-ref args (This must be done last) 
                int[] outRefArgMap = cache.OutRefArgMap;
                if (outRefArgMap.Length > 0) 
                { 
                    foreach (int index in outRefArgMap)
                    { 
                        ValidateReturnArg(outArgs[index], parameters[index].ParameterType);
                    }
                }
            } 

            // validate return value 
            //   (We don't validate Message.BeginAsync because the return value 
            //    is always an IAsyncResult and the method base is the one that
            //    represents the underlying synchronous method). 
            int callType = m.GetCallType();
            if ((callType & Message.CallMask ) != Message.BeginAsync)
            {
                Type returnType = cache.ReturnType; 
                if (returnType != null)
                { 
                    ValidateReturnArg(returnValue, returnType); 
                }
            } 

            m.PropagateOutParameters(outArgs, returnValue);
        } // PropagateOutParameters
 
        private static void ValidateReturnArg(Object arg, Type paramType)
        { 
            if (paramType.IsByRef) 
                paramType = paramType.GetElementType();
 
            if (paramType.IsValueType)
            {
                if (arg == null)
                { 
                    if (!(paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                        throw new RemotingException( 
                            Environment.GetResourceString("Remoting_Proxy_ReturnValueTypeCannotBeNull")); 
                }
                else if (!paramType.IsInstanceOfType(arg)) 
                {
                    throw new InvalidCastException(
                        Environment.GetResourceString("Remoting_Proxy_BadReturnType"));
                } 
            }
            else 
            { 
                if (arg != null)
                { 
                    if (!paramType.IsInstanceOfType(arg))
                    {
                        throw new InvalidCastException(
                            Environment.GetResourceString("Remoting_Proxy_BadReturnType")); 
                    }
                } 
            } 
        } // ValidateReturnArg
 
        // This is shared code path that executes when an EndInvoke is called
        // either on a delegate on a proxy
        // OR a regular delegate (called asynchronously).
        [System.Security.SecurityCritical]  // auto-generated 
        internal static IMessage EndInvokeHelper(Message reqMsg, bool bProxyCase)
        { 
            AsyncResult ar = reqMsg.GetAsyncResult() as AsyncResult; 
            IMessage retMsg = null; // used for proxy case only!
            if (ar == null) 
            {
                throw new RemotingException(
                    Environment.GetResourceString(
                        "Remoting_Message_BadAsyncResult")); 
            }
            if (ar.AsyncDelegate != reqMsg.GetThisPtr()) 
            { 
                throw new InvalidOperationException(Environment.GetResourceString(
                    "InvalidOperation_MismatchedAsyncResult")); 
            }
            if (!ar.IsCompleted)
            {
                // Note: using ThreadPoolAware to detect if this is a 
                // ThreadAffinity or Synchronization context.
                ar.AsyncWaitHandle.WaitOne( 
                        Int32.MaxValue, 
                        Thread.CurrentContext.IsThreadPoolAware);
            } 

            lock (ar)
            {
                if (ar.EndInvokeCalled) 
                    throw new InvalidOperationException(
                        Environment.GetResourceString( 
                            "InvalidOperation_EndInvokeCalledMultiple")); 

                ar.EndInvokeCalled = true; 


                IMethodReturnMessage mrm =
                    (IMethodReturnMessage) ar.GetReplyMessage(); 

                Contract.Assert( 
                    mrm != null, 
                    "Reply sink should ensure we have a reply message before signalling");
 
                // For the proxy case this is handled by RealProxy
                if (!bProxyCase)
                {
                    Exception e = mrm.Exception; 

                    if (e != null) 
                    { 
                        // throw e;
                        throw e.PrepForRemoting(); 
                    }
                    else
                    {
                        reqMsg.PropagateOutParameters( 
                            mrm.Args,
                            mrm.ReturnValue); 
                    } 
                }
                else 
                {
                    retMsg = mrm;
                }
                // Merge the call context back into the thread that 
                // called EndInvoke
                CallContext.GetLogicalCallContext().Merge( 
                    mrm.LogicalCallContext); 
            }
            // Will be non-null only for proxy case! 
            return retMsg;
        } // EndInvokeHelper

#if FEATURE_COMINTEROP 
        // itnerop methods
        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IntPtr GetCOMIUnknown(bool fIsMarshalled) 
        {
            // sub -class should override 
            return MarshalByRefObject.GetComIUnknown((MarshalByRefObject)GetTransparentProxy());
        }

        public virtual void SetCOMIUnknown(IntPtr i) 
        {
            // don't care 
        } 

        public virtual IntPtr SupportsInterface(ref Guid iid) 
        {
            return IntPtr.Zero;
        }
#endif // FEATURE_COMINTEROP 

        // Method used for traversing back to the TP 
        public virtual Object GetTransparentProxy() 
        {
            return _tp; 
        }

        internal MarshalByRefObject UnwrappedServerObject
        { 
            get { return (MarshalByRefObject) _serverObject; }
        } 
 
        internal virtual Identity IdentityObject
        { 
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            get
            {
                return (Identity) _identity; 
            }
 
            set 
            {
                _identity = value; 
            }
        }

        // Private method invoked by the transparent proxy 
        [System.Security.SecurityCritical]  // auto-generated
        private void PrivateInvoke(ref MessageData msgData, int type) 
        { 
            IMessage reqMsg = null;
            CallType callType = (CallType)type; 
            IMessage retMsg = null;
            int msgFlags = -1;

            // Used only for Construction case 
            RemotingProxy rp = null;
 
            // Create a message object based on the type of call 
            if(CallType.MethodCall == callType)
            { 
                Message msg = new Message();
                msg.InitFields(msgData);
                reqMsg = msg;
                msgFlags = msg.GetCallType(); 
            }
            else if (CallType.ConstructorCall == (CallType)callType) 
            { 
                // We use msgFlags to handle CallContext around
                // the virtual call to Invoke() 
                msgFlags = Message.[....];

                rp = this as RemotingProxy;
                ConstructorCallMessage ctorMsg = null; 
                bool bIsWellKnown = false;
                if(!IsRemotingProxy()) 
                { 
                    // Create a new constructor call message
                    // < 

                    ctorMsg = new ConstructorCallMessage(null, null, null, (RuntimeType)GetProxiedType());
                }
                else 
                {
                    // Extract the constructor message set in the first step of activation. 
                    ctorMsg = rp.ConstructorMessage; 
                    // If the proxy is a wellknown client proxy, we don't
                    // need to run the c'tor. 
                    Identity id = rp.IdentityObject;
                    if (id != null)
                        bIsWellKnown = id.IsWellKnown();
                } 

                if ((null == ctorMsg) || bIsWellKnown) 
                { 
                    // This is also used to short-circuit the activation path
                    // when we have a well known proxy that has already been 
                    // initialized (there's a race condition if we don't do this).
                    //

                    // This is a special case, where we have a remoting proxy 
                    // but the constructormessage hasn't been setup.
                    // so let us just bail out.. 
                    // this is currently used by ServicedComponent's for cross appdomain 
                    // pooling: <EMAIL>[....]</EMAIL>
                    // 
                    ctorMsg = new ConstructorCallMessage(null, null, null, (RuntimeType)GetProxiedType());
                    // Set the constructor frame info in the CCM
                    ctorMsg.SetFrame(msgData);
                    reqMsg = ctorMsg; 

                    // If this was the default ctor, check that default .ctor was called. 
                    if (bIsWellKnown) 
                    {
                        Contract.Assert(rp!=null, "RemotingProxy expected here!"); 
                        // Clear any cached ctorMsg on the RemotingProxy
                        rp.ConstructorMessage = null;

                        // We did execute a Connect. Throw if the client 
                        // code is also trying to use a non-default constructor at
                        // the same time. 
                        if (ctorMsg.ArgCount != 0) 
                        {
                            throw new RemotingException( 
                                Environment.GetResourceString(
                                    "Remoting_Activation_WellKnownCTOR"));
                        }
                    } 

                    // Create a constructor return message 
                    retMsg = 
                        new ConstructorReturnMessage((MarshalByRefObject)GetTransparentProxy(),
                            null, 
                            0,
                            null,
                            ctorMsg);
                } 
                else
                { 
                    // Set the constructor frame info in the CCM 
                    ctorMsg.SetFrame(msgData);
                    reqMsg = ctorMsg; 
                }
            }
            else
            { 
                Contract.Assert(false, "Unknown call type");
            } 
 
            // Make sure that outgoing remote calls are counted.
            ChannelServices.IncrementRemoteCalls(); 

            // For non-remoting proxies, EndAsync should not call Invoke()
            // because the proxy cannot support Async and the call has already
            // finished executing in BeginAsync 
            if (!IsRemotingProxy()
                && ((msgFlags&Message.EndAsync)==Message.EndAsync)) 
            { 

                Message msg = reqMsg as Message; 
                retMsg = EndInvokeHelper(msg, true);
                Contract.Assert(null != retMsg, "null != retMsg");
            }
 
            // Invoke
            Contract.Assert(null != reqMsg, "null != reqMsg"); 
            if (null == retMsg) 
            {
                // NOTE: there are cases where we setup a return message 
                // and we don't want the activation call to go through
                // refer to the note above for ServicedComponents and Cross Appdomain
                // pooling
 
                LogicalCallContext cctx = null;
                Thread currentThread = Thread.CurrentThread; 
                // Pick up or clone the call context from the thread 
                // and install it in the reqMsg as appropriate
                cctx = currentThread.GetLogicalCallContext(); 
                SetCallContextInMessage(reqMsg, msgFlags, cctx);

                // Add the outgoing "Header"'s to the message.
                cctx.PropagateOutgoingHeadersToMessage(reqMsg); 
                retMsg = Invoke(reqMsg);
 
                // Get the call context returned and set it on the thread 
                ReturnCallContextToThread(currentThread, retMsg, msgFlags, cctx);
 
                // Pull response "Header"'s out of the message
                CallContext.GetLogicalCallContext().PropagateIncomingHeadersToCallContext(retMsg);
            }
 
            if (!IsRemotingProxy()
                && ((msgFlags&Message.BeginAsync) == Message.BeginAsync)) 
            { 

                // This was a begin-async on a non-Remoting Proxy. For V-1 they 
                // cannot support Async and end up doing a [....] call. We need
                // to fill up here to make the call look like async to
                // the caller.
                // Create the async result to return 
                Message msg = reqMsg as Message;
                AsyncResult ar = new AsyncResult(msg); 
                // Tell the async result that the call has actually completed 
                // so it can hold on to the return message.
                ar.SyncProcessMessage(retMsg); 
                // create a returnMessage to propagate just the asyncResult back
                // to the caller's stack.
                retMsg = new ReturnMessage(ar, null, 0, null/*cctx*/, msg);
            } 

            // Propagate out parameters 
            HandleReturnMessage(reqMsg, retMsg); 

            // For constructor calls do some extra bookkeeping 
            if(CallType.ConstructorCall == callType)
            {
                // NOTE: It is the responsiblity of the callee to propagate
                // the out parameters 

                // Everything went well, we are ready to return 
                // a proxy to the caller 
                // Extract the return value
                MarshalByRefObject retObj = null; 
                IConstructionReturnMessage ctorRetMsg = retMsg as IConstructionReturnMessage;
                if(null == ctorRetMsg)
                {
                    throw new RemotingException( 
                        Environment.GetResourceString("Remoting_Proxy_BadReturnTypeForActivation"));
                } 
 
                ConstructorReturnMessage crm = ctorRetMsg as ConstructorReturnMessage;
                if (null != crm) 
                {
                    // If return message is of type ConstructorReturnMessage
                    // this is an in-appDomain activation. So no unmarshaling
                    // needed. 

                    retObj = (MarshalByRefObject)crm.GetObject(); 
                    if (retObj == null) 
                    {
                        throw new RemotingException( 
                            Environment.GetResourceString("Remoting_Activation_NullReturnValue"));
                    }
                }
                else 
                {
                    // Fetch the objRef out of the returned message and unmarshal it 
                    retObj = (MarshalByRefObject)RemotingServices.InternalUnmarshal( 
                                (ObjRef)ctorRetMsg.ReturnValue,
                                GetTransparentProxy(), 
                                true /*fRefine*/);

                    if (retObj == null)
                    { 
                        throw new RemotingException(
                            Environment.GetResourceString("Remoting_Activation_NullFromInternalUnmarshal")); 
                    } 
                }
 
                if (retObj != (MarshalByRefObject)GetTransparentProxy())
                {
                    throw new RemotingException(
                        Environment.GetResourceString( 
                            "Remoting_Activation_InconsistentState"));
                } 
 
                if (IsRemotingProxy())
                { 
                    // Clear any cached ctorMsg on the RemotingProxy
                    rp.ConstructorMessage = null;
                }
            } 
        }
 
        void SetCallContextInMessage( 
            IMessage reqMsg, int msgFlags, LogicalCallContext cctx)
        { 
            Contract.Assert(msgFlags != -1, "Unexpected msgFlags?");
            Message msg = reqMsg as Message;

            switch (msgFlags) 
            {
            case Message.[....]: 
                if (msg != null) 
                {
                    msg.SetLogicalCallContext(cctx); 
                }
                else
                {
                    ((ConstructorCallMessage)reqMsg).SetLogicalCallContext(cctx); 
                }
                break; 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        void ReturnCallContextToThread(Thread currentThread, IMessage retMsg, int msgFlags, LogicalCallContext currCtx)
        {
            if (msgFlags == Message.[....]) 
            {
                if (retMsg == null) 
                    return; 

                IMethodReturnMessage mrm = retMsg as IMethodReturnMessage; 
                if (mrm == null)
                    return;

                LogicalCallContext retCtx = mrm.LogicalCallContext; 
                if (retCtx == null) {
                    currentThread.SetLogicalCallContext(currCtx); 
                    return; 
                }
 
                if (!(mrm is StackBasedReturnMessage))
                {
                    LogicalCallContext oldCtx = currentThread.SetLogicalCallContext(retCtx);
                    if ((Object)oldCtx != (Object)retCtx) 
                    {
                        // If the new call context does not match the old call context, 
                        //   we must have gone remote. We need to keep the preserve 
                        //   the principal from the original call context.
                        IPrincipal principal = oldCtx.Principal; 
                        if (principal != null)
                            retCtx.Principal = principal;
                    }
                } 
                //for other types (async/one-way etc) there is nothing to be
                //done as we have just finished processing BeginInvoke or EndInvoke 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal virtual void Wrap()
        {
            // < 

 
 
            ServerIdentity serverID = _identity as ServerIdentity;
            if((null != serverID) && (this is RemotingProxy)) 
            {
                Contract.Assert(null != serverID.ServerContext, "null != serverID.ServerContext");
                SetStubData(this, serverID.ServerContext.InternalContextID);
            } 
        }
 
        protected RealProxy() 
        {
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
